﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Sockets;

namespace XmlServer.Host.Console
{
    class Program
    {
        static void Main(string[] args)
        {            
            System.Console.Clear();
            System.Console.WriteLine("*****************************************************************");
            System.Console.WriteLine("* XML Server Suite - Server System.Console                             *");
            System.Console.WriteLine("*****************************************************************");

            var ipAddress = PromptForNIC();
            

            System.Console.Write("Enter in the listening port (default is 8095): ");
            string _port = System.Console.ReadLine();
            int port = 0;
            if (!Int32.TryParse(_port, out port)) port = 8095;


            System.Console.Write("Enter in the number of worker threads to process requests (default is 20): ");
            string _numThreads = System.Console.ReadLine();
            int numThreads = 0;
            if (!Int32.TryParse(_numThreads, out numThreads)) numThreads = 20;

            // setup the operator directory
            string operatorsDirectory = Path.Combine(System.Environment.CurrentDirectory, "Operators");
            System.Console.WriteLine("Operators Directory = " + operatorsDirectory);

            System.Console.WriteLine();
            var dir = new DirectoryInfo(operatorsDirectory);
            
            if (dir.Exists)
            {
                System.Console.WriteLine("The operators directory does not exsit.  Please create the directory and copy the operator Dlls to the directory.");
                System.Console.WriteLine("For example, copy the EchoServer.dll and DelayServer.dll to the above server directory.");
                System.Console.WriteLine();
            }


            System.Console.WriteLine("Step 1 of 5: Creating the XML Server Listener");
            XmlServer.Server server = new XmlServer.Server();


            System.Console.WriteLine("Step 2 of 5: Setting the server listening ip address and port");
            server.ProcessingListener.Configuration.IPAddress = ipAddress;
            server.ProcessingListener.Configuration.Port = port;
            server.ProcessingListener.Configuration.OperatorsFolder = operatorsDirectory;
            server.ProcessingListener.Configuration.NumberOfThreads = numThreads;

            int priorityPort = port + 1;
            System.Console.WriteLine(string.Format("Step 3 of 5: Setting the port to {0} on the priority listener", priorityPort));
            server.PriorityListener.Configuration.IPAddress = ipAddress;
            server.PriorityListener.Configuration.Port = priorityPort;
            server.PriorityListener.Configuration.OperatorsFolder = operatorsDirectory;

            System.Console.WriteLine("Step 4 of 5: Setting up the events");
            server.ProcessingListener.ListenerDebugMessage += ProcessingListener_ListenerDebugMessage;            
            server.ProcessingListener.ListenerException += ProcessingListener_ListenerException;
            server.ProcessingListener.ListenerPaused += ProcessingListener_ListenerPaused;
            server.ProcessingListener.ListenerRequestCompleted += ProcessingListener_ListenerRequestCompleted;
            server.ProcessingListener.ListenerRequestServicing += ProcessingListener_ListenerRequestServicing;
            server.ProcessingListener.ListenerRequestStarted += ProcessingListener_ListenerRequestStarted;
            server.ProcessingListener.ListenerResumed += ProcessingListener_ListenerResumed;
            server.ProcessingListener.ListenerStarted += ProcessingListener_ListenerStarted;
            server.ProcessingListener.ListenerStopped += ProcessingListener_ListenerStopped;

            // you could add all the priority listener events too
            // For example:
            server.PriorityListener.ListenerStarted += PriorityListener_ListenerStarted;


            System.Console.WriteLine("Step 5 of 5: Starting the Listener");
            server.StartListening();

            
            System.Console.WriteLine("Press ESC to stop the Listener Server");
            do
            {
                while (!System.Console.KeyAvailable)
                {
                    // Do nothing
                }
            } while (System.Console.ReadKey(true).Key != System.ConsoleKey.Escape);
            
            server.Shutdown();
        }


        static string PromptForNIC()
        {
            System.Console.WriteLine("Please select the network card to listen on: ");

            IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());

            List<String> ips = new List<string>();
            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    ips.Add(ip.ToString());
                }

            }

            int count = 1;
            foreach (var ip in ips)
            {
                System.Console.WriteLine(String.Format("    {0}: {1}", count, ip));
                count++;
            }

            System.Console.Write("\nSelection: ");
            string selection = System.Console.ReadLine();

            int nic = 0;
            Int32.TryParse(selection, out nic);

            if (nic == 0)
            {
                System.Console.WriteLine("");
                System.Console.WriteLine("Invalid selection: The first NIC will be used to listen");
                nic = 1;
            }

            if (nic > host.AddressList.Length)
            {
                System.Console.WriteLine("");
                System.Console.WriteLine("Invalid selection: The first NIC will be used to listen");
                nic = 1;
            }

            return  ips[nic - 1].ToString();
        }

        public static void ProcessingListener_ListenerDebugMessage(object sender, string IPAddress, int Port, string Message)
        {
            System.Console.WriteLine(String.Format("+ Process Listener: Debug Message: {0}", Message));
        }

        public static void ProcessingListener_ListenerException(object sender, string ClassName, string MethodName, Exception err)
        {
            DisplayExecption(err);
        }

        public static void ProcessingListener_ListenerPaused(object sender, string IPAddress, int Port)
        {
            System.Console.WriteLine("+ Processing Listener: Paused");
        }

        public static void ProcessingListener_ListenerRequestCompleted(object sender, string ClientIPAddress, int ClientPort, string ReplyData, int Duration)
        {
            System.Console.WriteLine(String.Format("+ Process Listener: Request Completed, Reply = {0}", ReplyData));
        }

        public static void ProcessingListener_ListenerRequestServicing(object sender, string ClientIPAddress, int ClientPort, string RequestData)
        {
            System.Console.WriteLine(String.Format("+ Process Listener: Servicing Request, Request = {0}", RequestData));
        }

        public static void ProcessingListener_ListenerRequestStarted(object sender, string ClientIPAddress, int ClientPort)
        {
            System.Console.WriteLine("+ Processing Listener: Request Started");
            System.Console.WriteLine("Press ESC to stop the Listener Server");
        }

        public static void ProcessingListener_ListenerResumed(object sender, string IPAddress, int Port)
        {
            System.Console.WriteLine("+ Processing Listener: Resumed");
        }

        public static void ProcessingListener_ListenerStarted(object sender, string IPAddress, int Port)
        {
            System.Console.WriteLine("Successfully started the Listener on port " + Port.ToString());

            System.Console.WriteLine("Operators Loaded:");
            int count = 1;
            XmlServer.Listeners.Listener listener = (XmlServer.Listeners.Listener)sender;
            foreach (var operatorInvoker in listener.OperatorInvokers)
            {
                System.Console.WriteLine(String.Format("    {0}: {1}", count, operatorInvoker.Value.FullName));
                count++;
            }

            System.Console.WriteLine("Note: You can stop this server at any time by pressing ENTER on your keyboard.");
        }

        public static void ProcessingListener_ListenerStopped(object sender, string IPAddress, int Port)
        {
            System.Console.WriteLine("+ Processing Listener: Stopped");
        }

        public static void PriorityListener_ListenerStarted(object sender, string IPAddress, int Port)
        {
            System.Console.WriteLine("+ Priority Listener: Started");
            System.Console.WriteLine("Press ESC to stop the Listener Server");
        }

        private static void DisplayExecption(Exception err)
        {
            System.Console.WriteLine("Error: " + err.ToString());
            if (err.InnerException != null) DisplayExecption(err.InnerException);
        }


    }
}
